using LiJ.Http.Mos;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LiJ.Http.Extention
{
	/// <summary>
	///  请求基类
	/// </summary>
	public static class HttpClientExtention
	{
		private const string LineBreak = "\r\n";

		/// <summary>
		///   编码格式
		/// </summary>
		public static Encoding Encoding
		{
			get;
			set;
		} = Encoding.UTF8;


		/// <summary>
		///  执行请求方法
		/// </summary>
		/// <param name="client"></param>
		/// <param name="request"></param>
		/// <returns></returns>
		public static Task<HttpResponseMessage> RestSend(this HttpClient client, LHttpRequest request)
		{
			return client.RestSend(request, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
		}

		/// <summary>
		///  执行请求方法
		/// </summary>
		/// <param name="client"></param>
		/// <param name="request"></param>
		/// <param name="completionOption"></param>
		/// <returns></returns>
		public static Task<HttpResponseMessage> RestSend(this HttpClient client, LHttpRequest request, HttpCompletionOption completionOption)
		{
			return client.RestSend(request, completionOption, CancellationToken.None);
		}

		/// <summary>
		///  执行请求方法
		/// </summary>
		/// <param name="client"></param>
		/// <param name="request"></param>
		/// <param name="completionOption"></param>
		/// <param name="cancellationToken"></param>
		/// <returns></returns>
		public static Task<HttpResponseMessage> RestSend(this HttpClient client, LHttpRequest request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
		{
			HttpRequestMessage request2 = ConfigureReqMsg(request);
			if (request.TimeOutMilSeconds > 0)
			{
				client.Timeout = TimeSpan.FromMilliseconds((double)request.TimeOutMilSeconds);
			}
			return client.SendAsync(request2, completionOption, cancellationToken);
		}

		/// <summary>
		/// 配置请求
		/// </summary>
		/// <returns></returns>
		public static HttpRequestMessage ConfigureReqMsg(LHttpRequest request)
		{
			HttpRequestMessage obj = new HttpRequestMessage
			{
				RequestUri = (string.IsNullOrEmpty(request.AddressUrl) ? request.Uri : new Uri(request.AddressUrl)),
				Method = new HttpMethod(request.HttpMothed.ToString())
			};
            ConfigReqContent(obj, request);
			return obj;
		}

		/// <summary>
		///  配置使用的cotent
		/// </summary>
		/// <param name="reqMsg"></param>
		/// <param name="req"></param>
		/// <returns></returns>
		private static void ConfigReqContent(HttpRequestMessage reqMsg, LHttpRequest req)
		{
			if (req.HttpMothed == HttpMothed.Get)
			{
                req.RequestSet?.Invoke(reqMsg);
            }
			else if (req.HasFile)
			{
				string boundary = GetBoundary();
				MemoryStream memoryStream = new MemoryStream();
                WriteMultipartFormData(memoryStream, req, boundary);
				memoryStream.Seek(0L, SeekOrigin.Begin);
				reqMsg.Content = new StreamContent(memoryStream);
                req.RequestSet?.Invoke(reqMsg);
                reqMsg.Content.Headers.Remove("Content-Type");
				reqMsg.Content.Headers.TryAddWithoutValidation("Content-Type", string.Format("multipart/form-data;boundary={0}", boundary));
			}
			else
			{
				string normalFormData = GetNormalFormData(req);
				reqMsg.Content = new StringContent(normalFormData);
                req.RequestSet?.Invoke(reqMsg);
                if (reqMsg.Content.Headers.ContentType == null)
				{
					reqMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
				}
			}
		}

		/// <summary>
		/// 写入 Form 的内容值 【 非文件参数 + 文件头 + 文件参数（内部完成） + 请求结束符 】
		/// </summary> 
		/// <param name="memory"></param>
		/// <param name="request"></param>
		/// <param name="boundary"></param>
		private static void WriteMultipartFormData(Stream memory, LHttpRequest request, string boundary)
		{
			foreach (var formParameter in request.FormParameters)
			{
                WriteStringTo(memory, GetMultipartFormData(formParameter, boundary));
			}
			foreach (var fileParameter in request.FileParameters)
			{
                WriteStringTo(memory, GetMultipartFileHeader(fileParameter, boundary));
				fileParameter.Writer(memory);
                WriteStringTo(memory, "\r\n");
			}
            WriteStringTo(memory, GetMultipartFooter(boundary));
		}

		/// <summary>
		/// 写入 Form 的内容值（文件头）
		/// </summary>
		/// <param name="file"></param>
		/// <param name="boundary"></param>
		/// <returns></returns>
		private static string GetMultipartFileHeader(FileParameter file, string boundary)
		{
			string text = file.ContentType ?? "application/octet-stream";
			return string.Format("--{0}{1}Content-Disposition: form-data; name=\"{2}\"; filename=\"{3}\"{4}Content-Type: {5}{6}{7}", boundary, "\r\n", file.Name, file.FileName, "\r\n", text, "\r\n", "\r\n");
		}

		/// <summary>
		/// 写入 Form 的内容值（非文件参数）
		/// </summary>
		/// <param name="param"></param>
		/// <param name="boundary"></param>
		/// <returns></returns>
		private static string GetMultipartFormData(FormParameter param, string boundary)
		{
			return string.Format("--{0}{1}Content-Disposition: form-data; name=\"{2}\"{3}{4}{5}{6}", boundary, "\r\n", param.Name, "\r\n", "\r\n", param.Value, "\r\n");
		}

		/// <summary>
		/// 写入 Form 的内容值  （请求结束符）
		/// </summary>
		/// <param name="boundary"></param>
		/// <returns></returns>
		private static string GetMultipartFooter(string boundary)
		{
			return string.Format("--{0}--{1}", boundary, "\r\n");
		}

		/// <summary>
		/// 写入请求的内容信息 （非文件上传请求）
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		private static string GetNormalFormData(LHttpRequest request)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (var formParameter in request.FormParameters)
			{
				if (stringBuilder.Length > 1)
				{
					stringBuilder.Append("&");
				}
				stringBuilder.AppendFormat(formParameter.ToString(), Array.Empty<object>());
			}
			if (string.IsNullOrEmpty(request.CustomBody))
			{
				return stringBuilder.ToString();
			}
			if (stringBuilder.Length > 1)
			{
				stringBuilder.Append("&");
			}
			stringBuilder.Append(request.CustomBody);
			return stringBuilder.ToString();
		}

		/// <summary>
		/// 写入数据方法（将数据写入  webrequest）
		/// </summary>
		/// <param name="stream"></param>
		/// <param name="toWrite"></param>
		/// <returns>写入的字节数量</returns>
		private static void WriteStringTo(Stream stream, string toWrite)
		{
			byte[] bytes = Encoding.GetBytes(toWrite);
			stream.Write(bytes, 0, bytes.Length);
		}

		/// <summary>
		/// 创建 请求 分割界限
		/// </summary>
		/// <returns></returns>
		private static string GetBoundary()
		{
			StringBuilder stringBuilder = new StringBuilder();
			Random random = new Random();
			for (var i = 0; i < 10; i++)
			{
				var index = random.Next("abcdefghijklmnopqrstuvwxyz0123456789".Length);
				stringBuilder.Append("abcdefghijklmnopqrstuvwxyz0123456789"[index]);
			}
			return string.Format("-------{0}", stringBuilder);
		}
	}
}
